﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Faml.Frontend
{
    /// <summary>
    /// FamlExpressionClass is class of equal Faml expressions; it is used by the optimizer.
    /// </summary>
    public class FamlExpressionClass
    {
        private List<FamlExpression> expressions;
        private List<FamlExpressionClass> dependOnMe;
        private int inEdges = 0; // a number of classes that I am depending on
        private int evaluationIndex = -1;


        private object value;
        private FamlReferenceExpression refExpression = null;

        public FamlExpressionClass(FamlExpression exp)
        {
            expressions = new List<FamlExpression>();
            Add(exp);
        }

        private bool nonRemovable = false;

        /// <summary>
        /// This class cannot be removed or reduced by optimizer
        /// </summary>
        public bool NonRemovableClass
        {
            get { return nonRemovable; }
            set { nonRemovable = true; }
        }

        /// <summary>
        /// Gets a type of an expression from the class.
        /// </summary>
        public Type Type
        {
            get
            {
                return expressions[0].Type;
            }
        }

        /// <summary>
        /// Gets or sets a reference to FamlExpression for this class
        /// </summary>
        public FamlReferenceExpression FamlReference
        {
            get
            {
                return refExpression;
            }
            set
            {
                refExpression = value;
            }
        }


        /// <summary>
        /// Gets or sets evaluation index of the class.
        /// </summary>
        public int EvaluationIndex
        {
            get { return evaluationIndex; }
            set { evaluationIndex = value; }
        }

        /// <summary>
        /// Removes the class (and implicitly all its dependants) and clears all its expressions Class property.  
        /// </summary>
        public void RemoveClass()
        {
            if (dependOnMe != null)
                foreach (FamlExpressionClass dc in dependOnMe)
                {
                    dc.RemoveOneInEdge();
                }

            if (expressions != null)
                foreach (FamlExpression exp in expressions)
                {
                    exp.Class = null;
                }
        }

        /// <summary>
        /// Adds the specified class <paramref name="@class"/> that depends on this one.
        /// </summary>
        public void AddClassDependingOnMe(FamlExpressionClass @class)
        {
            if (dependOnMe == null)
                dependOnMe = new List<FamlExpressionClass>();

            dependOnMe.Add(@class);
            @class.inEdges++;
        }

        /// <summary>
        /// Gets the value that is true if there are classes that depends on this one.
        /// </summary>
        public bool HasDependingOnMe
        {
            get { return dependOnMe != null && dependOnMe.Count != 0; }
        }

        /// <summary>
        /// Gets a collection of classes those depend on this one.
        /// </summary>
        public List<FamlExpressionClass> DependingOnMe
        {
            get { return dependOnMe; }
        }

        /// <summary>
        /// Says that one class that this one depends on is removed.
        /// </summary>
        public void RemoveOneInEdge()
        {
            inEdges--;
        }

        /// <summary>
        /// Gets the value indicating whether there are classes that this one depends on.
        /// </summary>
        public bool IsDependantClass
        {
            get { return inEdges > 0; }
        }

        /// <summary>
        /// Gets the value of this class, i.e. the result of its expression's evaluation.
        /// </summary>
        public object Value
        {
            get { return value; }
        }

        /// <summary>
        /// Adds new expression that belongs to this class.
        /// </summary>
        /// <param name="expression">An expression that belongs to this class</param>
        public void Add(FamlExpression expression)
        {
            expressions.Add(expression);
            expression.Class = this;
        }

        /// <summary>
        /// Gets the power of this class.
        /// </summary>
        public int Power
        {
            get { return expressions.Count; }
        }

        /// <summary>
        /// Gets the height of the expressions those belongs to this class.
        /// </summary>
        public int Height
        {
            get { return expressions[0].Metadata.Height; }
        }

        /// <summary>
        /// Gets the node type for the expressions of this class.
        /// </summary>
        public FamlExpressionType ExpressionsType
        {
            get { return expressions[0].NodeType; }
        }

        /// <summary>
        /// Gets the boolean value shows whether this class doesn't depend on any parameter or it does.
        /// </summary>
        public bool IsIndependent
        {
            get { return expressions[0].NodeParameters.Count == 0; }
        }

        /// <summary>
        /// Gets the expression of this class.
        /// </summary>
        public FamlExpression Expression
        {
            get { return expressions[0]; }
        }

        /// <summary>
        /// Gets a collection of expressions those belong to the class.
        /// </summary>
        public IList<FamlExpression> Expressions
        {
            get { return expressions; }
        }

        public override string ToString()
        {
            return String.Format("Class [{0}], {1} items", Expression, this.Power);
        }
    }
}